#define _WIN32_WINNT 0x501
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#include <metahost.h>
#include <CChannel.h>

static HINSTANCE hDynImageBase = NULL;
WCHAR clrversion[] =  L"v4.0.30319";
WCHAR dllname[] = L"RDPAddins.exe";
WCHAR classname[] = L"RDPAddins.Program";
WCHAR functionname[] = L"MainC";
TCHAR path[MAX_PATH];
ICLRRuntimeHost* runtimeHost = NULL;
ICLRRuntimeInfo* runtimeInfo = NULL;
ICLRMetaHost* metaHost = NULL;

BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{
	
	HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost);
	if(SUCCEEDED(hr))
	{		
		hr = metaHost->GetRuntime(clrversion, IID_ICLRRuntimeInfo,(LPVOID*)&runtimeInfo);
		if (SUCCEEDED(hr))
		{
			
			hr = runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*) &runtimeHost);
			if (SUCCEEDED(hr))
			{
				hr = runtimeHost->Start();
				if (SUCCEEDED(hr))
				{
					DWORD retCode = 0;
					WCHAR entry[255];
					unsigned int r = (unsigned int)pEntryPoints;
					int c = -1;
					do
					{
						entry[++c] = r % 10 + 48;
						r = r / 10;
					}
					while(r > 0);
					entry[++c] = L'\0';
					GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)&hDynImageBase, &hDynImageBase);
					DWORD ret = GetModuleFileName(hDynImageBase, path, MAX_PATH);
					while(path[ret] != L'\\')
						ret--;
					c = -1;
					do
					{
						path[++ret] = dllname[++c];
					}
					while(dllname[c]);
					path[++ret] = L'\0';
					hr = runtimeHost->ExecuteInDefaultAppDomain(path, classname, functionname, entry, &retCode);
					if(SUCCEEDED(hr))
						return retCode;
				}
			}
		}
	}
	return FALSE;
}

extern "C" BOOL WINAPI _DllMainCRTStartup(HANDLE  hDllHandle, DWORD   dwReason, LPVOID  lpreserved) 
{
	switch (dwReason)
	{
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
			break;
		case DLL_PROCESS_DETACH:
			if(runtimeHost != NULL)
			{
				runtimeHost->Stop();
				runtimeHost->Release();
			}
			if(runtimeInfo!= NULL)
				runtimeInfo->Release();
			if(metaHost!=NULL)
				metaHost->Release();
			break;
	}
	return TRUE;
}


